# -*- coding: utf-8 -*-
"""
-------------------------------------------------
# @Project  :pythonProject
# @File     :violator_fall
# @Date     :2021/8/26 17:41
# @Author   :zhumenglong
# @Software :PyCharm
-------------------------------------------------
"""
import json
from wareHouse import *

class Fall:

    def __init__(self,file_path,Index_path,goal_path):
        self.file_path = file_path
        self.Index_path = Index_path
        self.goal_path = goal_path

    def get_keypoint1(self):
        with open(self.Index_path, 'r', encoding='utf-8') as fp:
            while True:
                file_name = fp.readline()[:-1]
                if len(file_name) > 0:
                    json_name = self.file_path + file_name + '_info.json'
                    pict_name = self.file_path + file_name + '.jpg'
                    with open(json_name, 'rb') as f:
                        # f.read()
                        json_info = json.loads(f.read())
                        img_info = method.cv2_imread(pict_name,-1)
                        for i in json_info:
                            if i == "person":
                                for num in json_info[i]:
                                    for j in num:
                                        if j == "box":
                                            cat_name = "person"
                                            xmin = int(num[j]['x'])
                                            ymin = int(num[j]['y'])
                                            xmax = int(num[j]['x']) + int(num[j]['width'])
                                            ymax = int(num[j]['y']) + int(num[j]['height'])
                                            color = (250, 0, 0)
                                            cv2.rectangle(img_info, (int(xmin), int(ymin)), (int(xmax), int(ymax)), color,
                                                          2)
                                            font = cv2.FONT_HERSHEY_SIMPLEX
                                            cv2.putText(img_info, cat_name, (int(xmin), int(ymin)), font, 1, color, 2)

                                        elif j == "key_point":

                                            keypoint_thresh_vis = 0.3

                                            keypoint = []
                                            for ii in num[j]:
                                                keypoint.append(ii)
                                            keypoint = np.array(keypoint)

                                            keypoint = keypoint.reshape((1, -1, 3))
                                            joint_visible = keypoint[:, :, 2] > keypoint_thresh_vis
                                            kpts_num = keypoint.shape[1]
                                            for i1 in range(keypoint.shape[0]):
                                                pts = keypoint[i1]
                                                for color_i, jp in zip(colors, main_joint_pairs):
                                                    if jp[0] >= kpts_num or jp[1] >= kpts_num: continue
                                                    if joint_visible[i1, jp[0]] and joint_visible[i1, jp[1]]:
                                                        pt0 = pts[jp, 0]
                                                        pt1 = pts[jp, 1]
                                                        pt0_0, pt0_1, pt1_0, pt1_1 = int(pt0[0]), int(pt0[1]), int(
                                                            pt1[0]), int(pt1[1])

                                                        cv2.line(img_info, (pt0_0, pt1_0), (pt0_1, pt1_1), color_i, 3)

                                            l_r, std_distance, left_fall, right_fall = Fall.fall_detection(self,img_info, "",
                                                                                                      keypoint, 1, 1, 0.3)
                                            up_name = str("(" + str(l_r) + "," + str(std_distance) + "," + str(
                                                left_fall) + "," + str(right_fall) + ")")
                                            if std_distance > 0:
                                                if left_fall > 0 or right_fall > 0:
                                                    cv2.putText(img_info, str(up_name),
                                                                (int(num['box']['x']), int(num['box']['y'] - 40)),
                                                                cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 250, 0), 1)
                                                else:
                                                    cv2.putText(img_info, str(up_name),
                                                                (int(num['box']['x']), int(num['box']['y'] - 40)),
                                                                cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 250, 0), 1)
                                            else:
                                                cv2.putText(img_info, str(up_name),
                                                            (int(num['box']['x']), int(num['box']['y'] - 40)),
                                                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 250, 0), 1)
                                        else:
                                            cv2.putText(img_info, str(num[j]),(1800, 200),cv2.FONT_HERSHEY_SIMPLEX,
                                                        2, (0, 250, 0), 2)
                        method.create_path(self.goal_path)

                        method.cv2_imwrite_jpg("./" + self.goal_path + "/" + file_name + ".jpg", img_info)
                else:
                    break

    def get_sim(self,f1, f2):
        return np.dot(np.array(f1), np.array(f2).T)  # 返回的是两个数组的点积，后边加.T表示行向量转化为列向量

    #                  图像，  "" ，17或24个关键点，关键点属性，   人体遮挡，      人体关键点分数
    def fall_detection(self,image, box, keypoint, keypoint_attr, person_occ, keypoint_thresh_vis=0.3):

        def pose_others(pts, nose2ankle, joint_visible):
            is_bend = None
            for calc_idx in range(1,3):
                if not joint_visible[nose2ankle[calc_idx][0]]: continue # shoulder on select side is must visible
                if not joint_visible[nose2ankle[calc_idx][1]]: continue # eblow on select side is must visible
                if not joint_visible[nose2ankle[calc_idx][2]]: continue # knee on select side is must visible
                # distance from shoulder to eblow
                jp = nose2ankle[calc_idx][:2]
                pt0 = pts[jp, 0]
                pt1 = pts[jp, 1]
                vec = np.array([pt0[1] - pt0[0], pt1[1] - pt1[0]])
                SE_dis = np.linalg.norm(vec)  # L2

                # distance from shoulder to knee
                jp = [nose2ankle[calc_idx][0], nose2ankle[calc_idx][2]]
                pt0 = pts[jp, 0]
                pt1 = pts[jp, 1]
                vec = np.array([pt0[1] - pt0[0], pt1[1] - pt1[0]])
                NA_dis = np.linalg.norm(vec)  # L2
                # print(calc_idx, NA_dis, SE_dis)
                is_bend = NA_dis < SE_dis * 2.5 # is_bend
                if is_bend: return calc_idx, not is_bend
            if is_bend is not None and is_bend == False: return -1, True # not bend
            #unknow is not need to fall down
            return -1, False

        def is_fall(pts, joint_pairs, joint_visible, attr):
            vec = [None] * 3
            for idx, jp in enumerate(joint_pairs):
                if joint_visible[jp[0]] and joint_visible[jp[1]]:
                    pt0 = pts[jp, 0]
                    pt1 = pts[jp, 1]
                    vec[idx] = np.array([pt0[1] - pt0[0], pt1[1] - pt1[0]])
                    x_norm = np.linalg.norm(vec[idx])  # L2
                    vec[idx] = vec[idx] / x_norm
            leg_val, thigh_val, shank_val, body_val = False, False, False, False
            if vec[2] is not None:
                body_val = Fall.get_sim(self,vec[2],np.array([0, 1])) < 1.0 / 2.0 # 1.0 / math.sqrt(2.0) # < cos(60)

            if body_val:
                if vec[0] is not None and vec[1] is not None:
                    leg_val = Fall.get_sim(self,vec[0], vec[1]) < math.cos(
                        110. / 180. * math.pi)  # math.sqrt(3.0) / -2.   #< cos(120) dun or tang
                if vec[0] is not None:
                    thigh_val = Fall.get_sim(self,vec[0], np.array([0, 1])) < 1.0 / 2.0  # 1.0 / math.sqrt(2.0) # < cos(60)
                if vec[1] is not None:
                    shank_val = Fall.get_sim(self,np.array([0, 1]), vec[1]) < math.sqrt(3.0) / -2.  # 1.0 / math.sqrt(2.0) # < cos(45)

                # print(vec[0], vec[1], leg_val, thigh_val, shank_val)
            return leg_val * 1 + thigh_val * 2 + shank_val * 4


        left_leg = [[11, 13], [13, 15], [5, 11]]  # [hip, knee], [knee, ankle], [shoulder, hip]
        right_leg = [[12, 14], [14, 16], [6, 12]]
        nose2ankle = [[0], [5, 7, 13], [6, 8, 14]] # nose, [shoulder, eblow, knee], [...]

        kpts_atrr = None  # keypoint_attr.reshape((1,-1,2))
        keypoint = keypoint.reshape((1, -1, 3))
        joint_visible = keypoint[:, :, 2] > keypoint_thresh_vis
        kpts_num = keypoint.shape[1]
        for i1 in range(keypoint.shape[0]):
            pts = keypoint[i1]
            attr = None  # kpts_atrr[i]

            l_r, std_distance = pose_others(pts, nose2ankle, joint_visible[i1])
            left_fall = is_fall(pts, left_leg, joint_visible[i1], attr)
            right_fall = is_fall(pts, right_leg, joint_visible[i1], attr)
        return (l_r, std_distance, left_fall, right_fall)  # 如果std_distance大于0，且（left_fall, right_fall）有大于0的就认为倒地

